home *** CD-ROM | disk | FTP | other *** search
/ 2,000 Greater & Lesser Mysteries / 2,000 Greater and Lesser Mysteries.iso / psychol / marble / help.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-10  |  20.6 KB  |  895 lines

  1. /*------------------------------------------------------------*/
  2. /* filename -       Help.cpp                                  */
  3. /*                                                            */
  4. /* function(s)                                                */
  5. /*                  Member function(s) of following classes   */
  6. /*                      THelpTopic                            */
  7. /*                      THelpIndex                            */
  8. /*                      THelpFile                             */
  9. /*                      THelpViewer                           */
  10. /*                      THelpWindow                           */
  11. /*------------------------------------------------------------*/
  12.  
  13. /*------------------------------------------------------------*/
  14. /*                                                            */
  15. /*    Turbo Vision -  Version 1.0                             */
  16. /*                                                            */
  17. /*                                                            */
  18. /*    Copyright (c) 1991 by Borland International             */
  19. /*    All Rights Reserved.                                    */
  20. /*                                                            */
  21. /*------------------------------------------------------------*/
  22.  
  23. #define Uses_TStreamableClass
  24. #define Uses_TPoint
  25. #define Uses_TStreamable
  26. #define Uses_ipstream
  27. #define Uses_opstream
  28. #define Uses_fpstream
  29. #define Uses_TRect
  30. #define Uses_TScrollBar
  31. #define Uses_TScroller
  32. #define Uses_TDrawBuffer
  33. #define Uses_TEvent
  34. #define Uses_TWindow
  35. #define Uses_TKeys
  36. #define Uses_TPalette
  37. #include <tv.h>
  38.  
  39. #if !defined( __HELP_H )
  40. #include "Help.h"
  41. #endif  // __HELP_H
  42.  
  43. #if !defined( __UTIL_H )
  44. #include "Util.h"
  45. #endif  // __UTIL_H
  46.  
  47. #if !defined( __STRING_H )
  48. #include <string.h>
  49. #endif  // __STRING_H
  50.  
  51. #if !defined( __LIMITS_H )
  52. #include <limits.h>
  53. #endif  // __LIMITS_H
  54.  
  55. #if !defined( __STAT_H )
  56. #include <sys\stat.h>
  57. #endif  // __STAT_H
  58.  
  59. #if !defined( __CTYPE_H )
  60. #include <ctype.h>
  61. #endif  // __CTYPE_H
  62.  
  63. #if !defined( __IO_H )
  64. #include <io.h>
  65. #endif  // __IO_H
  66.  
  67. #pragma warn -dsz
  68.  
  69. TCrossRefHandler crossRefHandler = notAssigned;
  70.  
  71. // THelpTopic
  72. const char * const near THelpTopic::name = "THelpTopic";
  73.  
  74. void THelpTopic::write( opstream& os )
  75. {
  76.     writeParagraphs( os );
  77.     writeCrossRefs( os );
  78.     
  79. }
  80.  
  81. void *THelpTopic::read( ipstream& is )
  82. {
  83.     readParagraphs( is );
  84.     readCrossRefs( is );
  85.     width = 0;
  86.     lastLine = INT_MAX; 
  87.     return this;
  88. }
  89.  
  90. TStreamable *THelpTopic::build()
  91. {
  92.     return new THelpTopic( streamableInit );
  93. }
  94.  
  95.  
  96. TStreamableClass RHelpTopic( THelpTopic::name,
  97.                                   THelpTopic::build,
  98.                                   __DELTA(THelpTopic)
  99.                                 );
  100.  
  101. THelpTopic::THelpTopic() : TObject()
  102. {
  103.     paragraphs = 0;
  104.     numRefs = 0;
  105.     crossRefs = 0;
  106.     width = 0;
  107.     lastOffset = 0;
  108.     lastLine = INT_MAX;
  109.     lastParagraph = 0;
  110. };
  111.  
  112. void THelpTopic::readParagraphs( ipstream& s )
  113. {
  114.     int  i, size;
  115.     TParagraph **pp;
  116.     int temp;
  117.  
  118.     s >> i;
  119.     pp = ¶graphs;
  120.     while ( i > 0)
  121.     {
  122.         s >> size;
  123.         *pp = new TParagraph;
  124.         (*pp)->text = new char[size];
  125.         (*pp)->size = (ushort) size;
  126.     s >> temp;
  127.         (*pp)->wrap = Boolean(temp);
  128.         s.readBytes((*pp)->text, (*pp)->size);
  129.         pp = &((*pp)->next);
  130.         --i;
  131.     }
  132.     *pp = 0;
  133. }
  134.  
  135. void THelpTopic::readCrossRefs( ipstream& s )
  136. {
  137.     int i;
  138.     TCrossRef *crossRefPtr;
  139.  
  140.     s >> numRefs;
  141.     crossRefs = new TCrossRef[numRefs];
  142.     for (i = 0; i < numRefs; ++i)
  143.         {
  144.         crossRefPtr = (TCrossRef *)crossRefs + i;
  145.         s.readBytes(crossRefPtr, sizeof(TCrossRef));
  146.         }
  147. }
  148.  
  149. void THelpTopic::disposeParagraphs()
  150. {
  151.     TParagraph *p, *t;
  152.  
  153.     p = paragraphs;
  154.     while (p != 0)
  155.         {
  156.         t = p;
  157.         p = p->next;
  158.         delete t->text; 
  159.         delete t;
  160.         }
  161. }
  162.  
  163.  
  164. THelpTopic::~THelpTopic()
  165. {
  166.     TCrossRef *crossRefPtr;
  167.  
  168.     disposeParagraphs();
  169.     if (crossRefs != 0)
  170.        {
  171.        crossRefPtr = (TCrossRef *)crossRefs;
  172.        delete [numRefs] crossRefPtr;
  173.        }
  174. }
  175.  
  176. void THelpTopic::addCrossRef( TCrossRef ref )
  177. {
  178.     TCrossRef *p;
  179.     TCrossRef *crossRefPtr;
  180.  
  181.     p =  new TCrossRef[numRefs+1];
  182.     if (numRefs > 0)
  183.         {
  184.         crossRefPtr = crossRefs;
  185.         memmove(p, crossRefPtr, numRefs * sizeof(TCrossRef));
  186.         delete [numRefs] crossRefPtr;
  187.         }
  188.     crossRefs = p;
  189.     crossRefPtr = crossRefs + numRefs;
  190.     *crossRefPtr = ref;
  191.     ++numRefs;
  192. }
  193.  
  194.  
  195. void THelpTopic::addParagraph( TParagraph *p )
  196. {
  197.     TParagraph  *pp, *back;
  198.  
  199.     if (paragraphs == 0)
  200.         paragraphs = p;
  201.     else
  202.         {
  203.         pp = paragraphs;
  204.         back = pp;
  205.         while (pp != 0)
  206.             {
  207.             back = pp;
  208.             pp = pp->next;
  209.             }
  210.         back->next = p;
  211.         }
  212.     p->next = 0;
  213. }
  214.  
  215. void THelpTopic::getCrossRef( int i, TPoint& loc, uchar& length,
  216.          int& ref )
  217. {
  218.     int oldOffset, curOffset, offset, paraOffset;
  219.     TParagraph *p;
  220.     int line;
  221.     TCrossRef *crossRefPtr;
  222.  
  223.     paraOffset = 0;
  224.     curOffset = 0;
  225.     oldOffset = 0;
  226.     line = 0;
  227.     crossRefPtr = crossRefs + i;
  228.     offset = crossRefPtr->offset;
  229.     p = paragraphs;
  230.     while (paraOffset + curOffset < offset)
  231.         {
  232.         oldOffset = paraOffset + curOffset;
  233.         wrapText(p->text, p->size, curOffset, p->wrap);
  234.         ++line;
  235.         if (curOffset >= p->size)
  236.             {
  237.             paraOffset += p->size;
  238.             p = p->next;
  239.             curOffset = 0;
  240.             }
  241.         }
  242.     loc.x = offset - oldOffset - 1;
  243.     loc.y = line;
  244.     length = crossRefPtr->length;
  245.     ref = crossRefPtr->ref;
  246. }
  247.  
  248. char *THelpTopic::getLine( int line )
  249. {
  250.     int offset, i;
  251.     TParagraph *p;
  252.     char buffer[256];
  253.  
  254.     if (lastLine < line)
  255.         {
  256.         i = line;
  257.         line -= lastLine;
  258.         lastLine = i;
  259.         offset = lastOffset;
  260.         p = lastParagraph;
  261.         }
  262.     else
  263.         {
  264.         p = paragraphs;
  265.         offset = 0;
  266.         lastLine = line;
  267.         }
  268.     buffer[0] = 0;
  269.     while (p != 0)
  270.     {
  271.         while (offset < p->size)
  272.         {
  273.             --line;
  274.             strcpy(buffer, wrapText(p->text, p->size, offset, p->wrap));
  275.             if (line == 0)
  276.                 {
  277.                 lastOffset = offset;
  278.                 lastParagraph = p;
  279.                 return buffer;
  280.                 }
  281.         }
  282.         p = p->next;
  283.         offset = 0;
  284.     }
  285.     buffer[0] = 0;
  286.     return buffer;
  287. }
  288.  
  289. int THelpTopic::getNumCrossRefs()
  290. {
  291.     return numRefs;
  292. }
  293.  
  294. int THelpTopic::numLines()
  295. {
  296.     int offset, lines;
  297.     TParagraph *p;
  298.  
  299.     offset = 0;
  300.     lines = 0;
  301.     p = paragraphs;
  302.     while (p != 0)
  303.         {
  304.         offset = 0; 
  305.         while (offset < p->size)
  306.             {
  307.             ++lines;
  308.             wrapText(p->text, p->size, offset, p->wrap);
  309.             }
  310.         p = p->next;
  311.         }
  312.     return lines;
  313. }
  314.  
  315. void THelpTopic::setCrossRef( int i, TCrossRef& ref )
  316. {
  317.     TCrossRef *crossRefPtr;
  318.  
  319.     if (i < numRefs)
  320.         {
  321.         crossRefPtr = crossRefs + i;
  322.         *crossRefPtr = ref;
  323.         }
  324. }       
  325.  
  326.  
  327. void THelpTopic::setNumCrossRefs( int i )
  328. {
  329.     TCrossRef  *p, *crossRefPtr;
  330.  
  331.     if (numRefs == i)
  332.         return;
  333.     p = new TCrossRef[i];
  334.     if (numRefs > 0)
  335.         {
  336.         crossRefPtr = crossRefs;
  337.         if (i > numRefs)
  338.             memmove(p, crossRefPtr, numRefs * sizeof(TCrossRef));
  339.         else
  340.             memmove(p, crossRefPtr, i * sizeof(TCrossRef));
  341.  
  342.         delete [numRefs] crossRefPtr; 
  343.         }
  344.     crossRefs = p;
  345.     numRefs = i;
  346. }
  347.  
  348.  
  349. void THelpTopic::setWidth( int aWidth )
  350. {
  351.     width = aWidth;
  352. }
  353.  
  354. void THelpTopic::writeParagraphs( opstream& s )
  355. {
  356.     int i;
  357.     TParagraph  *p;
  358.     int temp;
  359.  
  360.     p = paragraphs;
  361.     for (i = 0; p != 0; ++i)
  362.         p = p->next;
  363.     s << i;
  364.     for(p = paragraphs; p != 0; p = p->next)
  365.         {
  366.         s << p->size;
  367.         temp = int(p->wrap);
  368.         s << temp;
  369.         s.writeBytes(p->text, p->size);
  370.         }
  371. }
  372.  
  373.  
  374. void THelpTopic::writeCrossRefs( opstream& s )
  375. {
  376.     int i;
  377.     TCrossRef *crossRefPtr;
  378.  
  379.     s << numRefs;
  380.     if (crossRefHandler == notAssigned)
  381.         {
  382.         for(i = 0; i < numRefs; ++i)
  383.             {
  384.             crossRefPtr = crossRefs + i;
  385.             s << crossRefPtr->ref << crossRefPtr->offset << crossRefPtr->length;
  386.             }
  387.         }
  388.     else
  389.         for (i = 0; i < numRefs; ++i)
  390.             {
  391.             crossRefPtr = crossRefs + i;
  392.             crossRefHandler(s, crossRefPtr->ref);
  393.             s << crossRefPtr->offset << crossRefPtr->length;
  394.             }
  395. }
  396.  
  397. Boolean isBlank( char ch )
  398. {
  399.     if (isspace(ch))
  400.         return True;
  401.     else
  402.         return False;
  403. }
  404.  
  405. int scan( char *p, int offset, char c)
  406. {
  407.     char *temp1, *temp2;
  408.     
  409.     temp1 = p + offset;
  410.     temp2 = strchr(temp1, c);
  411.     if (temp2 == 0)
  412.        return 256;
  413.     else
  414.        {
  415.        if ((int)(temp2 - temp1) <= 256 )
  416.          return (int) (temp2 - temp1) + 1;
  417.        else
  418.          return 256;
  419.        }
  420. }
  421.  
  422. void textToLine( void *text, int offset, int length, char *line )
  423. {
  424.     strncpy(line, (char *)text+offset, length);
  425.     line[length] = 0;
  426. }
  427.  
  428. char *THelpTopic::wrapText( char *text, int size,
  429.           int& offset, Boolean wrap )
  430. {
  431.     char line[256];
  432.     int i;
  433.  
  434.     i = scan(text, offset, '\n');
  435.     if (i + offset > size )
  436.         i = size - offset;
  437.     if ((i >= width) && (wrap == True))
  438.         {
  439.         i = offset + width;
  440.         if (i > size)
  441.             i = size;
  442.         else
  443.             {
  444.             while((i > offset) && !(isBlank(text[i])))
  445.                 --i;
  446.             if (i == offset)
  447.                 i = offset + width;
  448.             else
  449.                 ++i;
  450.             }
  451.         if (i == offset)
  452.         i = offset + width;
  453.         i -= offset;
  454.         }
  455.     textToLine(text, offset, i, line);
  456.     if (line[strlen(line) - 1] == '\n')
  457.         line[strlen(line) - 1] = 0;
  458.     offset += i;
  459.     return line;
  460. }
  461.  
  462. // THelpIndex 
  463.  
  464. const char * const near THelpIndex::name = "THelpIndex";
  465.  
  466. void THelpIndex::write( opstream& os )
  467. {
  468.     long *indexArrayPtr;
  469.  
  470.     os << size;
  471.     for (int i = 0; i < size; ++i)
  472.         {
  473.         indexArrayPtr = index + i; 
  474.         os << *indexArrayPtr;
  475.         }
  476. }
  477.  
  478. void *THelpIndex::read( ipstream& is )
  479. {
  480.     long *indexArrayPtr;
  481.  
  482.     is >> size;
  483.     if (size == 0)
  484.         index = 0;
  485.     else
  486.         {
  487.         index =  new long[size];
  488.         for(int i = 0; i < size; ++i)
  489.             {
  490.             indexArrayPtr = index + i;
  491.             is >> *indexArrayPtr;
  492.             }
  493.         }
  494.     return this;
  495. }
  496.  
  497. TStreamable *THelpIndex::build()
  498. {
  499.     return new THelpIndex( streamableInit );
  500. }
  501.  
  502. TStreamableClass RHelpIndex( THelpIndex::name,
  503.                                   THelpIndex::build,
  504.                                   __DELTA(THelpIndex)
  505.                             );
  506.  
  507. THelpIndex::~THelpIndex()
  508. {
  509.     delete [size] index;
  510. }
  511.  
  512.  
  513. THelpIndex::THelpIndex(void): TObject ()
  514. {
  515.     size = 0;
  516.     index = 0;
  517. }
  518.  
  519. long THelpIndex::position(int i)
  520. {
  521.     long *indexArrayPtr;
  522.  
  523.     if (i < size)
  524.         {
  525.         indexArrayPtr = index + i;
  526.         return (*indexArrayPtr);
  527.         }
  528.     else
  529.         return -1;
  530. }
  531.  
  532. void THelpIndex::add( int i, long val )
  533. {
  534.     int delta = 10;
  535.     long *p;
  536.     int newSize;
  537.     long *indexArrayPtr;
  538.  
  539.     if (i >= size)
  540.         {
  541.         newSize = (i + delta) / delta * delta;
  542.         p = new long[newSize];
  543.         if (p != 0)
  544.             {
  545.             memmove(p, index, size * sizeof(long));
  546.             memset(p+size, 0xFF, (newSize - size) * sizeof(long));
  547.             }
  548.         if (size > 0)
  549.             {
  550.             delete [size] index;
  551.             }
  552.         index = p;
  553.         size = newSize;
  554.         }
  555.     indexArrayPtr = index + i;
  556.     *indexArrayPtr = val;
  557. }
  558.  
  559. // THelpFile
  560.  
  561. THelpFile::THelpFile( fpstream&  s )
  562. {
  563.     long magic;
  564.     int handle;
  565.     long size;
  566.  
  567.     magic = 0;
  568.     s.seekg(0);
  569.     handle = s.rdbuf()->fd();
  570.     size = filelength(handle);
  571.     if (size > sizeof(magic))
  572.         s >> magic;
  573.     if (magic != magicHeader)
  574.         {
  575.         indexPos = 12;
  576.         s.seekg(indexPos);
  577.         index =  new THelpIndex;
  578.         modified = True;
  579.         }
  580.     else
  581.         {
  582.         s.seekg(8);
  583.         s >> indexPos;
  584.         s.seekg(indexPos);
  585.         s >> index; 
  586.         modified = False;
  587.         }
  588.     stream = &s;
  589. }
  590.  
  591. THelpFile::~THelpFile(void)
  592. {
  593.     long magic, size;
  594.     int handle;
  595.  
  596.     if (modified == True)
  597.         {
  598.         stream->seekp(indexPos);
  599.         *stream << index;
  600.         stream->seekp(0);
  601.         magic = magicHeader;
  602.         handle = stream->rdbuf()->fd();
  603.         size = filelength(handle) - 8;
  604.         *stream << magic;
  605.         *stream << size;
  606.         *stream << indexPos;
  607.         }
  608.     delete stream;
  609.     delete index;
  610. }
  611.  
  612. THelpTopic *THelpFile::getTopic( int i )
  613. {
  614.     long pos;
  615.     THelpTopic *topic;
  616.  
  617.     pos = index->position(i);
  618.     if (pos > 0 )
  619.         {
  620.         stream->seekg(pos);
  621.         topic = new THelpTopic;
  622.         *stream >> topic;
  623.         return topic;
  624.         }
  625.     else return(invalidTopic());
  626. }
  627.  
  628. THelpTopic *THelpFile::invalidTopic()
  629. {
  630.     THelpTopic *topic;
  631.     TParagraph *para;
  632.     char invalidText[] = "\n No help available in this context.";
  633.  
  634.     topic =  new THelpTopic;
  635.     para =  new TParagraph;
  636.     para->text = newStr(invalidText);
  637.     para->size = strlen(invalidText);
  638.     para->wrap = False;
  639.     para->next = 0;
  640.     topic->addParagraph(para);
  641.     return topic;
  642. }
  643.  
  644. void THelpFile::recordPositionInIndex( int i )
  645. {
  646.     index->add(i, indexPos);
  647.     modified = True;
  648. }
  649.  
  650. void THelpFile::putTopic( THelpTopic *topic )
  651. {
  652.     stream->seekp(indexPos);
  653.     *stream << topic;
  654.     indexPos = stream->tellp();
  655.     modified = True;
  656. }
  657.  
  658. // THelpViewer
  659.  
  660. THelpViewer::THelpViewer( const TRect& bounds, TScrollBar* aHScrollBar,
  661.     TScrollBar* aVScrollBar, THelpFile *aHelpFile, ushort context )
  662.     : TScroller( bounds, aHScrollBar, aVScrollBar )
  663. {
  664.     options = (options | ofSelectable);
  665.     growMode = gfGrowHiX | gfGrowHiY;
  666.     hFile = aHelpFile;
  667.     topic = aHelpFile->getTopic(context);
  668.     topic->setWidth(size.x);
  669.     setLimit(78, topic->numLines());
  670.     selected = 1;
  671. }
  672.  
  673. THelpViewer::~THelpViewer()
  674. {
  675.     delete hFile;
  676.     delete topic;
  677. }
  678.  
  679. void THelpViewer::changeBounds( TRect& bounds )
  680. {
  681.     TScroller::changeBounds(bounds);
  682.     topic->setWidth(size.x);
  683.     setLimit(limit.x, topic->numLines());
  684. }
  685.  
  686. void THelpViewer::draw()
  687. {
  688.     TDrawBuffer b;
  689.     char line[256];
  690.     char buffer[256];
  691.     char *bufPtr;
  692.     int i, j, l;
  693.     int keyCount;
  694.     ushort normal, keyword, selKeyword, c;
  695.     TPoint keyPoint;
  696.     uchar keyLength;
  697.     int keyRef;
  698.  
  699.     normal = getColor(1);
  700.     keyword = getColor(2);
  701.     selKeyword = getColor(3);
  702.     keyCount = 0;
  703.     keyPoint.x = 0;
  704.     keyPoint.y = 0;
  705.     topic->setWidth(size.x);
  706.     if (topic->getNumCrossRefs() > 0)
  707.         {
  708.         do
  709.             {
  710.             ++keyCount;
  711.             topic->getCrossRef(keyCount-1, keyPoint, keyLength, keyRef);
  712.             } while ( (keyCount <= topic->getNumCrossRefs()) && (keyPoint.y < delta.y));
  713.         }
  714.     for (i = 1; i <= size.y; ++i)
  715.         {
  716.         b.moveChar(0, ' ', normal, size.x);
  717.         strcpy(line, topic->getLine(i + delta.y));
  718.         if (strlen(line) > delta.x)
  719.             {
  720.             bufPtr = line + delta.x; 
  721.             strncpy(buffer, bufPtr, size.x);
  722.             buffer[size.x] = 0;
  723.             b.moveStr(0, buffer, normal);
  724.             }
  725.         else
  726.             b.moveStr(0, "", normal);
  727.         while (i + delta.y == keyPoint.y)
  728.             {
  729.             l = keyLength;
  730.             if (keyPoint.x < delta.x )
  731.                 {
  732.                 l -= (delta.x - keyPoint.x);
  733.                 keyPoint.x = delta.x;
  734.                 }
  735.             if (keyCount == selected)
  736.                 c = selKeyword;
  737.             else
  738.                 c = keyword;
  739.             for(j = 0; j < l; ++j)
  740.                 b.putAttribute((keyPoint.x - delta.x + j),c);
  741.             ++keyCount;
  742.             if (keyCount <= topic->getNumCrossRefs())
  743.                 topic->getCrossRef(keyCount-1, keyPoint, keyLength, keyRef);
  744.             else
  745.                 keyPoint.y = 0;
  746.             }
  747.         writeLine(0, i-1, size.x, 1, b);
  748.         }
  749. }
  750.  
  751. TPalette& THelpViewer::getPalette() const
  752. {
  753.     static TPalette palette(cHelpViewer, sizeof( cHelpViewer)-1);
  754.     return palette;
  755. }
  756.  
  757. void THelpViewer::makeSelectVisible( int selected, TPoint& keyPoint,
  758.          uchar& keyLength, int& keyRef )
  759. {
  760.     TPoint d;
  761.  
  762.     topic->getCrossRef(selected, keyPoint, keyLength, keyRef);
  763.     d = delta;
  764.     if (keyPoint.x < d.x)
  765.         d.x = keyPoint.x;
  766.     if (keyPoint.x > d.x + size.x)
  767.         d.x = keyPoint.x - size.x;
  768.     if (keyPoint.y < d.y)
  769.         d.y = keyPoint.y;
  770.     if (keyPoint.y > d.y + size.y)
  771.         d.y = keyPoint.y - size.y;
  772.     if ((d.x != delta.x) || (d.y != delta.y))
  773.          scrollTo(d.x, d.y);
  774. }
  775.  
  776. void THelpViewer::switchToTopic( int keyRef )
  777. {
  778.     if (topic != 0)
  779.         delete topic;
  780.     topic = hFile->getTopic(keyRef);
  781.     topic->setWidth(size.x);
  782.     scrollTo(0, 0);
  783.     setLimit(limit.x, topic->numLines());
  784.     selected = 1;
  785.     drawView();
  786. }
  787.  
  788. void THelpViewer::handleEvent( TEvent& event )
  789. {
  790.  
  791.     TPoint keyPoint, mouse;
  792.     uchar keyLength;
  793.     int keyRef;
  794.     int keyCount;
  795.  
  796.  
  797.     TScroller::handleEvent(event);
  798.     switch (event.what)
  799.         {
  800.  
  801.         case evKeyDown:
  802.             switch (event.keyDown.keyCode)
  803.                 {
  804.                 case kbTab:
  805.                     ++selected;
  806.                     if (selected > topic->getNumCrossRefs())
  807.                         selected = 1;
  808.                     if ( topic->getNumCrossRefs() != 0 )
  809.                         makeSelectVisible(selected-1,keyPoint,keyLength,keyRef);
  810.                     break;
  811.                 case kbShiftTab:
  812.                     --selected;
  813.                     if (selected == 0)
  814.                         selected = topic->getNumCrossRefs();
  815.                     if ( topic->getNumCrossRefs() != 0 )
  816.                         makeSelectVisible(selected-1,keyPoint,keyLength,keyRef);
  817.                     break;
  818.                 case kbEnter:
  819.                     if (selected <= topic->getNumCrossRefs())
  820.                         {
  821.                         topic->getCrossRef(selected-1, keyPoint, keyLength, keyRef);
  822.                         switchToTopic(keyRef);
  823.                         }
  824.                     break;
  825.                 case kbEsc:
  826.                     event.what = evCommand;
  827.                     event.message.command = cmClose;
  828.                     putEvent(event);
  829.                     break;
  830.                 default:
  831.                     return;
  832.                 }
  833.             drawView();
  834.             clearEvent(event);
  835.             break;
  836.  
  837.         case evMouseDown:
  838.             mouse = makeLocal(event.mouse.where);
  839.             mouse.x += delta.x;
  840.             mouse.y += delta.y;
  841.             keyCount = 0;
  842.  
  843.             do
  844.             {
  845.                 ++keyCount;
  846.                 if (keyCount > topic->getNumCrossRefs())
  847.                     return;
  848.                 topic->getCrossRef(keyCount-1, keyPoint, keyLength, keyRef);
  849.             } while (!((keyPoint.y == mouse.y+1) && (mouse.x >= keyPoint.x) &&
  850.                   (mouse.x < keyPoint.x + keyLength)));
  851.             selected = keyCount;
  852.             drawView();
  853.             if (event.mouse.doubleClick)
  854.                 switchToTopic(keyRef);
  855.             clearEvent(event);
  856.             break;
  857.  
  858.         case evCommand:
  859.             if ((event.message.command == cmClose) && (owner->state && sfModal != 0))
  860.                 {
  861.                 endModal(cmClose);
  862.                 clearEvent(event);
  863.                 }
  864.             break;
  865.         }
  866. }
  867.  
  868. // THelpWindow 
  869.  
  870. THelpWindow::THelpWindow( THelpFile *hFile, ushort context ):
  871.        TWindow( TRect(0,0,50,18), "Help", wnNoNumber ),
  872.        TWindowInit( &THelpWindow::initFrame)
  873. {
  874.     TRect r(0, 0, 50, 18);
  875.     options = (options | ofCentered);
  876.     r.grow(-2,-1);
  877.     insert(new THelpViewer (r,
  878.       standardScrollBar(sbHorizontal | sbHandleKeyboard),
  879.       standardScrollBar(sbVertical | sbHandleKeyboard), hFile, context));
  880. }
  881.  
  882. TPalette& THelpWindow::getPalette() const
  883. {
  884.     static TPalette palette(cHelpWindow, sizeof( cHelpWindow)-1);
  885.     return palette;
  886. }
  887.  
  888.  
  889. void notAssigned( opstream& , int )
  890. {
  891. }
  892.  
  893. #pragma warn .dsz
  894.  
  895.